/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.mzk.oai.metadataRepository;

import cz.mzk.oai.metadataRepository.tools.CannotReadDirectoryException;
import cz.mzk.oai.metadataRepository.metadata.MetadataFormat;
import cz.mzk.oai.metadataRepository.tools.FileTools;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.validation.SchemaFactory;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.xml.sax.SAXException;

/**
 *
 * @author Martin Rehanek, Martin.Rehanek@gmail.com
 * http://www.edankert.com/validate.html
 */
public class MetadataValidator {

    private static MetadataValidator instance;
    private Map<MetadataFormat, SAXReader> readers;

    private MetadataValidator() {
        readers = new HashMap<MetadataFormat, SAXReader>(3);
        SAXParserFactory parserFactory = SAXParserFactory.newInstance();
        SchemaFactory schemaFactory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
        for (MetadataFormat format : MetadataFormat.values()) {
            try {
                parserFactory.setSchema(schemaFactory.newSchema(format.getSchemaUrl()));
                SAXParser parser = parserFactory.newSAXParser();
                readers.put(format, new SAXReader(parser.getXMLReader()));
            } catch (ParserConfigurationException ex) {
                Logger.getLogger(MetadataValidator.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SAXException ex) {
                Logger.getLogger(MetadataValidator.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public static MetadataValidator instanceOf() {
        if (instance == null) {
            instance = new MetadataValidator();
        }
        return instance;
    }

    /**
     * @param metadataFormat
     * @return SAXReader that validates documents according to the schema of metadataFormat
     */
    public SAXReader getValidatingSAXReader(MetadataFormat metadataFormat) {
        return readers.get(metadataFormat);
    }

    /**
     * Validates file using external schema obtained from format object. Interlan schema present in the document is ignored
     * @param file file to validate
     * @param format
     * @param printErrors
     * @return true if valid 
     */
    public boolean isValid(File file, MetadataFormat format, boolean printErrors) {
        SAXReader reader = readers.get(format);
        try {
            reader.read(file);
        } catch (DocumentException ex) {
            if (printErrors) {
                System.out.println(ex.getMessage());
            }
            return false;
        }
        return true;
    }

    /**
     * Tries to parse all files in directory and prints out their total number and number of those,
     * that are not valid according to format
     * @param dir
     * @param format
     * @param printNamesOfInvalidFiles
     * @return array containting: 1. total number of files and 2. nubmer of invalid files
     * @throws CannotReadDirectoryException if the files in directory could not be read
     */
    public int[] validateDir(File dir, MetadataFormat format, boolean printNamesOfInvalidFiles) throws CannotReadDirectoryException {
        List<String> filenames = FileTools.readFilenames(dir);
        int counter = 0;
        int validCounter = 0;
        System.out.println("Validating files in " + dir.getAbsolutePath());
        System.out.println("Xml schema: " + format.getSchemaUrl().toString());
        for (String filename : filenames) {
            File xmlFile = new File(dir.getAbsoluteFile() + File.separator + filename);
            if (xmlFile.isFile()) {//ignore directories
                /*try {
                    Thread.sleep(1);
                } catch (InterruptedException ex) {
                    Logger.getLogger(MetadataValidator.class.getName()).log(Level.SEVERE, null, ex);
                }*/

                counter++;
                if (isValid(xmlFile, format, false)) {
                    validCounter++;
                } else {
                    if (printNamesOfInvalidFiles) {
                        System.out.println(filename);
                    }
                }
            }
           /* if (counter % 10 == 0) {
                System.out.println("So far processed files: " + counter);
                System.out.println("So far invalid: " + (counter - validCounter));
            }*/
        }
        int[] result = new int[2];
        result[0] = counter;
        result[1] = validCounter;
        System.out.println("Number of files: " + counter);
        System.out.println("Number of invalid: " + (counter - validCounter));
        return result;
    }
}
